<?php
/**
 * 工厂类
 * 用户创建框架的类对象
 */

/// 类定义开始
class Factory
{
	/**
	 * 获取控制器类实例
	 *
	 * 实例化，并返回一个控制器对象
	 */
	public static function getController($class_name)
	{
		static $_instance = array();
		$identify = to_guid_string($class_name);

		/// 如果还未初始化，或者是终端脚本
		if (IS_CLI || (!isset($_instance[$identify])))
		{
			$path = function_exists('getControllerClassPath') ? getControllerClassPath($class_name) : C('CONTROLLER_PATH');

			$ctrl_file = $path.'/'.$class_name.'.controller.php';

			if (!is_file($ctrl_file)) throw_exception('加载控制器文件时出现异常，可能是控制器不存在。ctrl-file:'.$ctrl_file);

			require_once($ctrl_file);

			$class_name = parse_name($class_name.'_controller', 1);

			$o = new $class_name();

			$_instance[$identify] = $o;
		}

		return $_instance[$identify];
	}

	/**
	 * 获取模块类实例
	 *
	 * 实例化并返回一个模块对象
	 */
	public static function getModule($class_name, $public_lib = false)
	{
		static $_instance = array();
		$identify = to_guid_string($class_name);

		/// 如果还未初始化，或者是终端脚本
		if (IS_CLI || (!isset($_instance[$identify])))
		{
			if ( $public_lib ) {
				$path = CORE_ROOT . '/../public_lib/modules';
			} else {
				$path = function_exists('getModuleClassPath') ? getModuleClassPath($class_name) : C('MODULE_PATH');
			}

			$module_file = $path.'/'.$class_name.'.module.php';

			if (!is_file($module_file)) {
				trigger_error(__FUNCTION__.': module file no found: '.$module_file, E_USER_ERROR);
			}

			require_once($module_file);

			$class_name = parse_name($class_name.'_module', 1);

			$o = new $class_name();

			$_instance[$identify] = $o;
		}

		return $_instance[$identify];
	}

	/**
	 * 获取数据层实例
	 *
	 * 返回一个数据层class对象
	 */
	public static function getData($class_name)
	 {
		static $_instance = array();
		$identify = to_guid_string($class_name);

		/// 如果还未初始化，或者是终端脚本
		if (IS_CLI || (!isset($_instance[$identify])))
		{
			$path = function_exists('getDataClassPath') ? getDataClassPath($class_name) : C('DATA_PATH');

			$data_file = $path.'/'.$class_name.'.data.php';

			if (!is_file($data_file)) {
				trigger_error(__FUNCTION__.': data file no found: '.$data_file, E_USER_ERROR);
			}

			require_once($data_file);

			$class_name = parse_name($class_name.'_data', 1);

			$o = new $class_name();

			$_instance[$identify] = $o;
		}

		return $_instance[$identify];
	}

	/**
	 * 获取SQL语句模板
	 *
	 * 返回一个SQL语句模板
	 */
	public static function getSql($class_name, $data_file='')
	{
		static $_cache = array();
		$identify = to_guid_string($class_name);

		/// 如果还未初始化，或者是终端脚本
		if (IS_CLI || (!isset($_cache[$identify])))
		 {
			$path = function_exists('getSqlClassPath') ? getSqlClassPath($class_name) : C('SQL_PATH');

			$sql_file = $path.'/'.$class_name.'.sql.php';

			/// 判断sql文件是否存在
			if (!is_file($sql_file)) {
				trigger_error(__FUNCTION__.': '.$sql_file.' is not a file, DbDispatcher::loadSql: '.$data_file, E_USER_ERROR);
			}

			$sql_content = include $sql_file;

			/// 判断sql内容是否合法
			if (!is_array($sql_content)) {
				trigger_error(__FUNCTION__.': '.$sql_file.' content invalid, DbDispatcher::loadSql: '.$data_file, E_USER_ERROR);
			}

			$_cache[$identify] = $sql_content;
		}

		return $_cache[$identify];

	}

	/**
	 * 获取助手类实例
	 *
	 * 实例化并返回一个助手对象
	 *
	 * @deprecated v2.0 - 2010-5-9 本方法不再推荐使用，框架version>=2.0将不再推荐大家使用helper，请改用公用函数/module类处理相关逻辑
	 */
	public static function getHelper($class_name, $return_obj=true)
	{
		/// 如果只是纯粹的include
		if (!$return_obj)
		{
			$path = function_exists('getHelperClassPath') ? getHelperClassPath($class_name) : C('HELPER_PATH');

			$helper_file = $path.'/'.$class_name.'.helper.php';

			if (!is_file($helper_file)) {
				trigger_error(__FUNCTION__.': helper file no found: '.$helper_file, E_USER_ERROR);
			}

			require_once($helper_file);
			return ;
		}

		static $_instance = array();
		$identify = to_guid_string($class_name);

		if (IS_CLI || (!isset($_instance[$identify])))
		{
			$path = function_exists('getHelperClassPath') ? getHelperClassPath($class_name) : C('HELPER_PATH');

			$helper_file = $path.'/'.$class_name.'.helper.php';

			if (!is_file($helper_file)) {
				trigger_error(__FUNCTION__.': helper file no found: '.$helper_file, E_USER_ERROR);
			}

			require_once($helper_file);

			$class_name = parse_name($class_name.'_helper', 1);

			$o = new $class_name();

			$_instance[$identify] = $o;
		}

		return $_instance[$identify];
	}

	/**
	 * 输出视图
	 */
	public static function getView($filename, $data=array(), $output=true, $public_lib = false)
	{
		if ($data)
		{
			if (is_array($data))
			{
//				foreach ($data as $k => $v) { if (!isset($$k)) $$k = $v; }			// replace this loop with 'extract' function. php internal is much more faster. by jingwei
				extract($data,EXTR_SKIP);
			}
			else if (is_object($data)) {
				$data = get_object_vars($data);
			}
			else {
				trigger_error(__FUNCTION__.': unsupported variable type of data', E_USER_ERROR);
			}
		}

		if ( $public_lib ) {
			$path = CORE_ROOT . '/../public_lib/views';
		} else {
			$path = function_exists('getViewClassPath') ? getViewClassPath($filename) : C('VIEW_PATH');
		}

		$view_file = $path.'/'.$filename.'.view.php';

		/// 判断view的缓存文件是否存在，且不过期
		$view_cache_file = RUNTIME_PATH.md5($filename).basename($view_file);

		if (!is_file($view_file)) {
			trigger_error(__FUNCTION__.': view file no found: '.$view_file, E_USER_ERROR);
		}

		$view_mtime = filemtime($view_file);

		/// test, deploy才会采用编译后的view文件
		if (in_array(RUN_MOD, array('test', 'deploy')) && is_file($view_cache_file) && ($view_mtime < filemtime($view_cache_file)))
		{
			/// view缓存文件合法
		}
		else
		{
			/// 重新生成view缓存文件
			$view_content = Factory::compileView($view_file);

			/// 替换模板分隔符
			$view_content = str_replace('{ldelim}', '{', $view_content);
			$view_content = str_replace('{rdelim}', '}', $view_content);

			/// 保存view缓存文件
			file_put_contents($view_cache_file, $view_content);
		}

		if ($output) {
			return require($view_cache_file);
		}
		else {
			ob_start();
			require $view_cache_file;
			$view_content = ob_get_clean();

			return $view_content;
		}
	}

	/**
	 * 编译Data文件
	 *
	 * 返回编译后的data content
	 */
	public static function compileData($data_file)
	{
		$data_content = file_get_contents($data_file);

		while (preg_match('/^(.*?)[\'"]sql[\'"]\s*=>\s*DbDispatcher\s*::\s*loadSql\(\s*[\'"]\s*([a-zA-Z0-9_\-\.]+)\s*[\'"]\s*\)(.*)$/si', $data_content, $match)) {

			$sql_content = Factory::getSql($match[2], $data_file);

			$data_content = $match[1]."'sql'=>".var_export($sql_content, true).$match[3];
		}

		return $data_content;
	}

	/**
	 * 编译视图文件
	 *
	 * 返回编译后的view content
	 */
	public static function compileView($view_file)
	 {
		$view_content = file_get_contents($view_file);

		while (preg_match('/^(.*?)\{\s*include\s+file\s*=\s*[\'"](.*?)[\'"]\}(.*)$/si', $view_content, $match)) {

			$include_file = realpath(dirname($view_file).'/'.$match[2]);

			if (!is_file($include_file)) {
				trigger_error(__FUNCTION__.': view file no found: '.$include_file, E_USER_ERROR);
			}

			$include_content = Factory::compileView($include_file);

			$view_content = $match[1].$include_content.$match[3];
		}

		return $view_content;
	}
}

